/*
File:		foxfuncs.prg
Version:	1.2
Author:		Alex Antypenko
Description:	Foxpro command for (x)Harbour
Status:		Public Domain
Notes:		This is the library that contains the implementation FoxPro functions.

		SCATTER MEMVAR ...
		SCATTER ...TO ARRAY
		GATHER ....
		SCAN ... ENDSCAN
		_USE

		minisql
	
		CREATE TABLE 	
		CREATE DBF
		INSERT INTO ...
		SELECT 
*/

#include "error.ch"
#include "set.ch"
#include "hbfoxlib.ch"

#ifdef __XHARBOUR__
 #include "hbcompat.ch"
 STATIC t_aScope
#else
 #include "xhb.ch"
 THREAD STATIC t_aScope
#endif

****************************************************************
****************************************************************
Function fox_ScanBegin(cfor,bfor,bwhile,nRecords,nRecord,lRest,lNoOptimize)
 LOCAL h,f,oScope:={=>}
 t_aScope:={}

 if !used()
	return Nil
 endif
 oScope 		:= Hash()
 oScope["cFor"]		:= cFor 
 oScope["nRecords"]	:= iif(nRecords==NIL,lastrec(),nRecords)
 oScope["nCount"]	:= 0
 if valtype(nRecord)=="N"
	goto nRecord
	lRest := .t.
	oScope["nRecords"] := 1
 endif
 oScope["bWhile"]	:= bWhile
 oScope["bFor"]		:= bFor
 oScope["rm_filter"]	:= NIL
 if lNoOptimize .or. nRecord != NIL
	oScope["cFor"] := NIL
 else
	if (!empty(DbFilter()) .and. !empty(cfor))
		oScope["rm_filter"] := DbFilter()
		h := DbFilter()+' .AND. '+ALLTRIM(cfor)
        dbSetFilter( {|| &h}, h ) //SET FILTER TO &h
	elseif !empty(cfor)
        dbSetFilter( {|| &cfor}, cfor )
	endif
 endif

 if valtype(lRest)=="L" .and. lRest
 else
	goto top
 endif
 aadd(t_aScope,oScope)
return oScope
****************************************************************
function fox_ScanNext(oScope)
	if oScope == NIL
			oScope := atail(t_aScope)
	endif
	if oScope["nCount"] != 0
		skip
	endif
	while !eof()
		oScope["nCount"] ++
		if oScope["bWhile"] != NIL .and. ! eval(oScope["bWhile"])
			return .f.
		endif
		if oScope["nCount"] > oScope["nRecords"]
			return .f.
		endif
		if oScope["bFor"] == NIL .or. eval(oScope["bFor"])
			return .t.
		endif
		skip
	enddo
return .f.
****************************************************************
function fox_ScanEnd(oScope)
	if oScope == NIL
           oScope := atail(t_aScope)
	endif
	if !empty(oScope["cFor"])
		dbclearfilter()
		if oScope["rm_filter"] != NIL
			SET FILTER TO &(oScope["rm_filter"])
		endif
	endif
    asize(t_aScope, len(t_aScope)-1 )
return .t.

Function fox_fieldBlank(nField)
LOCAL xFiledsData:=.F.
DO CASE
    CASE FieldType(nField)=="C"
        xFiledsData := ''
    CASE FieldType(nField)=="N"
        xFiledsData := 0
    CASE FieldType(nField)=="L"
        xFiledsData := .F.
    CASE FieldType(nField)=="M"
        xFiledsData := ''
    CASE FieldType(nField)=="D"
        xFiledsData := DATE()
ENDCASE
Return xFiledsData

function fox_UseArea(db,alias,rdd,in,again,new,  share, ro, noUpdate, desc,ilist,xOrder,cTag,xOf,codepage )

        local i,old_rdd:=RddSetDefault(rdd),lNewArea:=.F.

	    IF new
        	select 0
        EndIf
        IF in != NIL //.and. in != 0
        	select(in)
        EndIf

        IF empty(db)
        	rddSetDefault(old_rdd)
        	return Nil
        EndIf
/*        if len(ilist)==1
        	//ilist[1]:=
        endif
*/      //IIF(in==0,.T.,.F.)
        dbUseArea(  NIL , rdd, db, alias, share, ro .or. noUpdate,codepage)
        for i=1 to len(iList)
      		ordListAdd( iList[i] )
        next
        ordSetFocus(xOrder,cTag)
        ordSetFocus(xOf,cTag)
        IF desc
        	ordDescend()
        EndIf
return Nil

**************************************************
* create table as SQL query "f1 t1(l1,d1), f2 t2 ,...."
******
function fox_CreateTable(tablename,data,ddriver)
	local i,ch,m:={},filename
	local flag:=1,f:=.f.
	local fname:="",ftype:="",flen:="",fdec:=""
	//i=at(" ",data)
	//filename:=alltrim(substr(data,1,i-1))
    filename:=alltrim(tablename)
	data:=alltrim(substr(data,1))
	if !(  left(data,1)=="(" .and. right(data,1)==")"  )
		i:=errorNew()
		i:description:="Sql syntax error:"+data
		i:genCode:=EG_SYNTAX
		i:operation:="CREATE TABLE"
		break(i)
	endif
	data:=alltrim(substr(data,2,len(data)-2))
	do while !empty(data)
		 ch:=left(data,1)
		 data:=substr(data,2)
		 if ch=="," .and. !f //end of description field
			aadd(m,{alltrim(fname), alltrim(ftype),val(flen),val(fdec)})
			flag:=1; f:=.f.
			fname:="";ftype:="";flen:="";fdec:=""
			data:=alltrim(data)
			loop
		 endif
		 if ch=="," .and. f
			flag++
			data:=alltrim(data)
			loop
		 endif
		 if ch==" "
			flag++
			data:=alltrim(data)
			loop
		 endif
		 if ch=="("
			flag:=3
			f:=.t.
			data:=alltrim(data)
			loop
		 endif
		 if ch==")"
			flag:=5
			f:=.f.
			data:=alltrim(data)
			loop
		 endif
		 do case
			case flag==1
				fname+=ch
			case flag==2
				ftype+=ch
			case flag==3
				flen+=ch
			case flag==4
				fdec+=ch
		 endcase
	enddo
	aadd(m,{alltrim(fname), alltrim(ftype),val(flen),val(fdec)})
	dbcreate(filename,m,ddriver)
return Nil

**************************************************
* INSERT INTO filename data VALUES valData VIA ddriver
* INSERT INTO filename FROM ARRAY array VIA ddriver
* INSERT INTO filename FROM MEMVAR VIA ddriver
********************************************************
function fox_InsertData(_filename,data,valData,ddriver)
    local i,j,d,fields:={},values,filename,lSelect:=.F.
    local olddriver
	i=at(" ",data)
	i:=iif(i==0,len(data)+1,i)

	filename:= _filename //alltrim(substr(data,1,i-1))
	data:=alltrim(substr(data,1)) //
	//ddriver:=iif(ddriver==NIL,rddSetDefault(),ddriver)
    if ddriver!=NIL
     olddriver:=RddSetDefault(ddriver)
    Endif
    if Select( filename ) != 0
     DbSelectArea(Select( filename ))
    Else
      DbUseArea(.T.,ddriver,filename)
      lSelect:=.T.
    Endif

	if empty(data) // fields list is empty
		for i=1 to fcount()
			aadd(fields,FieldName(i))
		next
	else
		if !(  left(data,1)=="(" .and. right(data,1)==")"  )
			use
			i:=errorNew()
			i:description:="Sql syntax error:"+data
			i:genCode:=EG_SYNTAX
			i:operation:="INSERT INTO"
			break(i)
		endif
		data:=substr(data,2,len(data)-2)
        fields:=HB_ATokens( data,",")//, .F., .F. )
	endif
	if valtype(valData) == "A"
		values:=valData
	else
      if valtype(valData)=="U"
		values:={}
		for i=1 to len(fields)
			j:=memvarBlock(fields[i])
			if j!=NIL
				aadd(values,eval(j) )
			else
				aadd(values, NIL )
			endif
		next
	  else
		if !(  left(valData,1)=="(" .and. right(valData,1)==")"  )
			use
			i:=errorNew()
			i:description:="Sql syntax error:"+valData
			i:genCode:=EG_SYNTAX
			i:operation:="INSERT INTO... VALUES"
			break(i)
		endif
		valData:=substr(valData,2,len(valData)-2)
		//values:=split(valData,",")
        values:=HB_ATokens( valData,",")
		for i=1 to len(values)
			if left(values[i],1)=="{"
				values[i]=substr(values[i],2,len(values[i])-2)
				values[i]=ctod(values[i])
			else
				values[i]=&(values[i])
			endif
		next
	  endif
	endif
	DbAppend()
	for i=1 to len(fields)
		j:=FieldPos(fields[i])
		if j>0 .and. i<=len(values) .and. values[i]!=NIL
			FieldPut(j,values[i])
		endif
	next
    IF lSelect
	 DbCloseArea()
    EndIf
return Nil
*******************************************
* FSIZE(<cFieldName>[,<cTableAlias>]) 
********************************************
function fox_FSize(_fieldName,cTableAlias)
	Local _retFieldSize:=0,lSelect:=.F.

    lSelect:=_selectTable(cTableAlias,.T.)

    _retFieldSize:= IIF(_fieldName == NIL,FieldSize(1),FieldSize( FieldPos(_fieldName)))

    IF lSelect
	 DbCloseArea()
    EndIf
return _retFieldSize
*******************************************
* SEEK <eExpression> [<soft: SOFTSEEK>] [<last: LAST>] TAG <cTagName> IN <cTableAlias> 
********************************************
function fox_Seek(_eExpr,_soft,_last,_cTableAlias,_cTagName)
    Local _retSeekState:= .F.,lSelect:=.F.,lIsTag:=.F.

    lSelect:=_selectTable(_cTableAlias,.T.)

    If _cTagName != NIL
     OrdSetfocus(_cTagName)     
     lIsTag:=.T.
    Endif    
	_retSeekState:= dbSeek( _eExpr, if( _soft, .T., NIL ), if( _last, .T., NIL ) )
    IF lSelect
	 DbCloseArea()
    EndIf
    IF lIsTag
	 OrdSetFocus() 
    EndIf
Return _retSeekState

Function _selectTable(cpTableAlias,lShared)
  Local lSelectState:=.F. 
  if cpTableAlias == NIL
        cpTableAlias:= Alias(Select())
  endif
  if Select( cpTableAlias ) != 0
    DbSelectArea(Select( cpTableAlias ))
  Else
    //DbUseArea(.T.,,cpTableAlias,,iif(lShared != Nil .and. lShared,.T.,.F.))
    DbUseArea(.T.,,cpTableAlias)
    lSelectState:=.T.
  Endif

Return lSelectState

**************************************************
* SELECT .... FROM .....
******

function fox_Select(sQuery)
   local oQuery := LocalSqlQueryNew()
   local tmp,i
   Local aSelectData:={}

    //? sQuery 
	//wait
    oQuery:parse(sQuery)
	oQuery:parseFrom()
	oQuery:parseTo()
	oQuery:openDB()
	oQuery:parseFields()
	oQuery:parseOrder()
	oQuery:parseGroup()
    //? "oQuery:where 1 ",oQuery:where
	//wait ///santy/
	oQuery:where:=oQuery:parseExpr(oQuery:where)
	oQuery:where:=oQuery:logicalOptimizeExpr(oQuery:where) //oQuery:where
	tmp:=oQuery:makeFilters(oQuery:where,.f.)
    //? "oQuery:having 1 ",oQuery:having
	//wait ///santy/
    if !(HB_IsNIL(tmp))
		oQuery:filter:=atail(tmp)
		asize(tmp,len(tmp)-1)
		oQuery:filters:=tmp
    Endif
    //? "oQuery:having 1 ",oQuery:having
	//wait ///santy/
	if !empty(oQuery:having)
		oQuery:having:=oQuery:parseExpr(oQuery:having)
		oQuery:having:=oQuery:logicalOptimizeExpr(oQuery:having)
		tmp:=oQuery:makeFilters(oQuery:having,.t.)

        if !(HB_IsNIL(tmp))
		  oQuery:hFilter:=atail(tmp)
	    endif
    endif

	oQuery:run()
	oQuery:outResult()
	oQuery:closeOut()
	oQuery:closeDB()
return Nil

Function localSql_SelectQuery(_Fields_data,_from_data,_FilterCondition,_group_data,_having_data,_orderby_data,_into_data)
	? _Fields_data,_from_data,_FilterCondition,_group_data,_having_data,_orderby_data,_into_data
Return Nil